<?php

/**
 * CrugeStoredUser
 *
 *  Modelo que realiza la persistencia de components.CrugeUser
 *
 * @property integer $iduser
 * @property string $username
 * @property string $email
 * @property string $password
 * @property string $authkey
 * @property integer $state
 * @property integer $totalsessioncounter
 * @property integer $currentsessioncounter
 * @property string $regdate    fecha de registro
 * @property string $actdate    fecha de activacion
 * @property string $logondate    ultimo login exitoso
 * @author: Christian Salazar H. <christiansalazarh@gmail.com> @salazarchris74
 * @license protected/modules/cruge/LICENSE
 */
class CrugeStoredUser extends CActiveRecord implements ICrugeStoredUser {

    public $_fields = array();
    public $deleteConfirmation; // required on 'delete'
    public $newPassword; // declararlo 'safe'
    // terminos y condiciones, caso registration,
    public $terminosYCondiciones;
    public $verifyCode;
    // establecer a true si se quiere saltar la validacion de captcha.
    // ver acerca de: cruge\components\CrugeUserManager.php::createBlankUser
    public $bypassCaptcha;

    public function getCustomFieldValue($fieldname, $defValue = "") {
        $field = $this->getCustomField($fieldname);
        if ($field != null)
            return $field->getFieldValue();
        return $defValue;
    }

    public function getCustomField($fieldname) {
        foreach ($this->getFields() as $obj)
            if ($fieldname == $obj->fieldname)
                return $obj;
        return null;
    }

    public function getUserDescription() {
        $fieldNames = CrugeUtil::config()->userDescriptionFieldsArray;
        $tmp = "";
        if (in_array("username", $fieldNames))
            $tmp .= "," . $this->username;
        if (in_array("email", $fieldNames))
            $tmp .= "," . $this->email;
        if ($fieldNames != null)
            foreach ($fieldNames as $fname)
                if (($fname != "username") && ($fname != "email"))
                    $tmp .= "," . $this->getCustomFieldValue($fname, "nohay_" . $fname);
        if ($tmp == "")
            $tmp = $this->getUsername();
        return ltrim($tmp, ", ");
    }

    /* es un loadModel de uso multiple. $modo puede ser: 'iduser','username' o 'email' para
      indicar por cual campo se quiere cargar el modelo.
      @returns ICrugeStoredUser
     */

    public static function loadModel($id, $modo = 'iduser') {
        return self::model()->findByAttributes(array($modo => $id));
    }

    /* entrega un array con los nombres de los atributos clave para orden, de primero el userid */

    public static function getSortFieldNames() {
        return array('iduser', 'username', 'email', 'state', 'logondate');
    }

    public function getStateName() {
        return Yii::app()->user->um->getStateName($this->state);
    }

    /*
      recibe un array de instancias de ICrugeField previamente cargada de valores
     */

    public function setFields($arFields) {
        $this->_fields = $arFields;
    }

    public function getFields() {
        if ($this->_fields == null) {
            return array();
        }
        return $this->_fields;
    }

    public function setAttributes($values, $safeOnly = true) {

        if (count($this->getFields()) > 0) {
            $test = __CLASS__ . ".setAttributes:\n";
            foreach ($values as $k => $v) {
                $test .= "[{$k}={$v}]\n";
            }
            $test .= "\nparse field values:\n";
            foreach ($values as $fieldName => $value) {
                $test .= "{$fieldName}...";

                $boolFound = false;
                foreach ($this->getFields() as $f) {
                    if ($f->fieldname == $fieldName) {
                        $test .= " found. setfieldvalue:[{$value}]\n";
                        $f->setFieldValue($value);
                        $boolFound = true;
                        break;
                    }
                }
                if ($boolFound == false) {
                    $test .= " [not found]\n";
                }
            }
            Yii::log($test, "info");
        }

        parent::setAttributes($values);
    }

    public function validate($attributes = null, $clearErrors = true) {
        // si el metodo de autenticacion es solo email, y, username es blanco
        // se genera uno automaticamente:
        if ($this->scenario == 'insert') {
            $declared_authmodes = CrugeUtil::config()->availableAuthModes;
            if (count($declared_authmodes == 1)) {
                if (($declared_authmodes[0] == 'email') && ($this->username == '')) {
                    $um = new CrugeUserManager();
                    $this->username = $um->generateNewUserName($this->email);
                } else
                if (($declared_authmodes[0] == 'username') && ($this->email == '')) {
                    $this->email = $this->username . '@noemail.local';
                }
            }
        }

        // realiza la validacion normal sobre los atributos de este modelo
        $validateResult = parent::validate();

        // ahora realiza la validacion sobre aquellos campos personalizados
        // y copia todos los errores al objeto mayor ($this)
        //
        foreach ($this->getFields() as $f) {
            if ($f->validateField() == false) {
                $this->addErrors($f->getErrors());
                $validateResult = false;
            }
        }

        return $validateResult;
    }

    public function save($runValidation = true, $attributes = null) {
        Yii::log(__METHOD__, "info");
        if ($this->hasErrors()) {
            Yii::log(__METHOD__ . " return false, has errors.", "info");
            return false;
        }

        // importante aqui:
        // primero debe guardar el usuario (this) y luego los campos
        // si se hiciera al reves y el escenario fuese 'insert' entonces al crear el CrugeFieldValue // se generaria un error porque el user->iduser no existiria aun.
        //
        $ok = parent::save();
        $this->saveFields();

        Yii::log(__METHOD__ . " returns: [" . $ok . "]", "info");
        return $ok;
    }

    public function saveFields() {
        foreach ($this->getFields() as $f) {
            // buscar el objeto ICrugeFieldValue, darle valores y guardarlo
            $crugeFieldValueInst = Yii::app()->user->um->loadICrugeFieldValue($this, $f);
            $boolOk = false;
            if ($crugeFieldValueInst != null) {
                $crugeFieldValueInst->value = $f->getFieldValue();
                $boolOk = $crugeFieldValueInst->save();
            }
            Yii::log(
                    "\n" . __METHOD__ . " \nfieldname='" . $f->fieldname . "'\nfieldvalue='" . $f->getFieldValue()
                    . "'\n boolOk=[" . $boolOk . "]\ncrugeFieldValueInst=[" . ($crugeFieldValueInst == null ? 'null' : 'not null') . "]\n\n", "info"
            );
        }
    }

    /**
      @retuns string nombre de usuario (para login).
     */
    public function getUserName() {
        return $this->username;
    }

    public function getEmail() {
        return $this->email;
    }

    public function tableName() {
        return CrugeUtil::getTableName('user');
    }

    public function getPrimaryKey() {
        return $this->iduser;
    }

    public static function listModels($param = array()) {
        return self::model()->findAllByAttributes($param);
    }

    public function getUpdateUrl() {
        return 'index.php?r=test' . $this->getPrimaryKey();
    }

    /**
     * Returns the static model of the specified AR class.
     * @return CrugeStoredUser the static model class
     */
    public static function model($className = __CLASS__) {
        return parent::model($className);
    }

    /**  hay un escenario llamado 'internal', que es puesto por CrugeUserManager::save()
     *   para poder guardar atributos especificos sin ser afectado por las reglas para formularios
     *
     *
     *
     * @return array validation rules for model attributes.
     */
    public function rules() {
        return array(
            array(
                'username',
                'match',
                'pattern' => '/^[a-zA-Z0-9\_\-\.]{3,45}$/'
                ,
                'message' => CrugeTranslator::t('logon', 'Invalid username')
            ),
            array('username,email', 'required'),
            array('newPassword', 'safe', 'on' => 'update'),
            array('newPassword', 'required', 'on' => 'insert, manualcreate'),
            array('newPassword', 'length', 'min' => 6, 'max' => 20),
            array(
                'newPassword',
                'match'
                ,
                'pattern' => '/^[a-zA-Z0-9@#$%]{6,20}$/'
                ,
                'message' => CrugeTranslator::t(
                        'logon', 'Password may contain numbers or symbols ({symbols}) and between {min} and {max} characters', array('{symbols}' => '@#$%', '{min}' => 6, '{max}' => 20)
                )
            ),
            array('username, password', 'length', 'max' => 64),
            array('state', 'numerical', 'integerOnly' => true),
            array('authkey', 'length', 'max' => 100),
            array('email', 'email'),
            array('email', 'length', 'max' => 100),
            array('username,email', 'validate_unique'),
            array('deleteConfirmation', 'required', 'on' => 'delete'),
            array(
                'deleteConfirmation',
                'compare',
                'compareValue' => '1'
                ,
                'on' => 'delete',
                'message' => CrugeTranslator::t('logon', 'Please, confirm checking the checkbox')
            ),
            array(
                'terminosYCondiciones',
                'required'
                ,
                'requiredValue' => '1'
                ,
                'on' => 'insert'
                ,
                'message' => CrugeTranslator::t('logon', 'Please, check if you understand and accept the terms of use'),
            ),
            array(
                'verifyCode',
                $this->_getCaptchaRule(),
                'on' => 'insert',
                'message' => CrugeTranslator::t('logon', 'Security code is mandatory'),
            ),
            array(
                'verifyCode',
                'captcha',
                'on' => 'insert',
                'allowEmpty' => true,
                'message' => CrugeTranslator::t('logon', 'Security code is invalid'),
            ),
            array('iduser, username, email, state, logondate', 'safe', 'on' => 'search'),
        );
    }

    /**
      al establecer $_crugeStoredUser->bypassCaptcha = true;
      entonces el captcha no sera tomado en cuenta.

      esta funcion es util cuando se quiere crear un nuevo usuario de cruge por la via del API.
     */
    private function _getCaptchaRule() {
        if (Yii::app()->user->um->getDefaultSystem()->getn('registerusingcaptcha') == 1) {
            // el administrador decidio pedir captcha para registrar los usuarios,
            // 	pero quiza el flag bypassCaptcha este activo.
            if ($this->bypassCaptcha == true) {
                // captcha es requerido, pero sera no sera tomado en cuenta.
                $this->verifyCode = null;
                return 'safe';
            } else {
                return 'required';
            } // captcha es requerido
        } else {
            // el administrador ha deshabilitado el uso de captcha.
            $this->verifyCode = null;
            return 'safe';
        }
    }

    public function validate_unique($att, $params) {
        $model = self::model()->findByAttributes(array($att => $this[$att]));
        if ($model != null) {
            $duptext = CrugeTranslator::t('logon', '\'{attribute}\' already in use', array('attribute' => $att));
            if ($this->scenario == 'insert') {
                $this->addError($att, $duptext);
                return;
            }
            if ($this->scenario == 'update') {
                if ($this->iduser != $model->iduser) {
                    $this->addError($att, $duptext);
                }
                return;
            }
        }
    }

    /**
     * @return array relational rules.
     */
    public function relations() {
        // NOTE: you may need to adjust the relation name and the related
        // class name for the relations automatically generated below.
        return array(
            'sessions' => array(self::HAS_MANY, 'crugesession', 'iduser'),
        );
    }

    /**
     * @return array customized attribute labels (name=>label)
     */
    public function attributeLabels() {
        return array(
            'idusuario' => ucfirst(CrugeTranslator::t('usuario#')),
            'username' => ucfirst(CrugeTranslator::t('username')),
            'email' => ucfirst(CrugeTranslator::t('correo')),
            'password' => ucfirst(CrugeTranslator::t('clave')),
            'authkey' => ucfirst(CrugeTranslator::t('llave de autenticacion')),
            'state' => ucfirst(CrugeTranslator::t('estado de la cuenta')),
            'newPassword' => ucfirst(CrugeTranslator::t('clave')),
            'deleteConfirmation' => ucfirst(CrugeTranslator::t('confirmar eliminacion')),
            'regdate' => ucfirst(CrugeTranslator::t('registrado')),
            'actdate' => ucfirst(CrugeTranslator::t('activado')),
            'logondate' => ucfirst(CrugeTranslator::t('ultimo acceso')),
            'terminosYCondiciones' => ucfirst(CrugeTranslator::t('comprendo y acepto, por favor registrarme')),
        );
    }

    /**
     * Retrieves a list of models based on the current search/filter conditions.
     * @return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.
     */
  

    public function search() {
        // Warning: Please modify the following code to remove attributes that
        // should not be searched.

        $criteria = new CDbCriteria;

        $criteria->compare('iduser', $this->iduser);
        $criteria->compare('username', $this->username, true);
        $criteria->compare('email', $this->email, true);
        $criteria->compare('state', $this->state);
        $criteria->compare('logondate', $this->logondate);

        return new CActiveDataProvider($this, array(
            'criteria' => $criteria,
            'sort' => array(
                'defaultOrder' => array('iduser' => true),
            ),
        ));
    }

}
